home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / cuj1008.zip / RAMEY.ZIP / RECORD.C < prev    next >
C/C++ Source or Header  |  1991-10-14  |  8KB  |  293 lines

  1. /*
  2. Postman's Sort (R) Version 1.0
  3. Copyright (c) Robert Ramey 1991. All Rights Reserved
  4. */
  5.  
  6. #include <fcntl.h>
  7. #include <io.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <assert.h>
  11. #include <links.h>
  12. #include "psort.h"
  13. #include "key.h"
  14. #include "record.h"
  15. #include "arg.h"
  16.  
  17. STACK *d_stack;
  18. RECORD *((*infunc)()) = rec_variable;
  19. size_t record_size
  20.     = DEFAULT_RECORD_SIZE;    /* max size of fixed or variable length record */
  21. size_t data_size = 0;        /* space required for fields, links etc. */
  22. char *record_buffer = NULL;    /* buffer to hold variable length record */
  23. int delimiter =  '\t';        /* field delimiter */
  24.  
  25. void *
  26. need(STACK *, SEG_SIZE);    /* defined in sort.c */
  27. RECORD *
  28. rec_get(char *, SEG_SIZE, FILE *);
  29. void
  30. rec_fill(RECORD *);
  31. void
  32. rec_windup(void);
  33.  
  34. /**********************************************************************
  35. rec_init - get command line info for record functions
  36. **********************************************************************/
  37. void
  38. rec_init(argc, argv)
  39. int argc;
  40. char *argv[];
  41. {
  42.     RANGE range;
  43.     unsigned int i;
  44.  
  45.     /* process key information */
  46.     key_init(argc, argv);
  47.     data_size = record_offset + sizeof(ADDRESS) + 1;
  48.  
  49.     /* analize arguments in command line */
  50.     i = arg_find(argc, argv, "-d");
  51.     if(i == -1)
  52.         i = arg_find(argc, argv, "-D");
  53.     if(i != -1){
  54.         argv[i] = "";
  55.         if(++i >= argc
  56.         || *argv[i] == '-'
  57.         || *argv[i] == '0')
  58.             error("-d switch muse specify delimiter char in apostrophes");
  59.         arg_value(argv[++i], &delimiter);
  60.         argv[i] = "";
  61.     }
  62.     i = arg_find(argc, argv, "-s");
  63.     if(i == -1)
  64.         i == arg_find(argc, argv, "-S");
  65.     if(i != -1){
  66.         argv[i] = "";
  67.         if(++i >= argc
  68.         || *argv[i] == '-'
  69.         || *argv[i] == '0'){
  70.             error("-s switch must specify record width or range");
  71.         }
  72.         else{
  73.             arg_range(argv[i], &range);
  74.             argv[i] = "";
  75.             if(range.start == range.end){
  76.                 record_size = range.start;
  77.                 infunc = rec_fixed;
  78.                 setmode(fileno(stdin), O_BINARY);
  79.                 setmode(fileno(stdout), O_BINARY);
  80.             }
  81.             else{
  82.                 record_size = range.end;
  83.                 record_buffer = malloc(record_size + 1);
  84.                 if(record_buffer == (char *)NULL)
  85.                     error("Couldn't get space for record buffer");
  86.             }
  87.         }
  88.     }
  89.     if(record_buffer == (char *)NULL){
  90.         record_buffer = malloc(record_size + 1);
  91.         if(record_buffer == (char *)NULL)
  92.             error("Couldn't get space for record buffer");
  93.     }
  94.     if(record_buffer != (char *)NULL){
  95.         if(atexit(rec_windup))
  96.             error("Couldn't register record windup");
  97.     }
  98.     return;
  99. }
  100. /**********************************************************
  101. rec_windup - return unused memory area
  102. ***********************************************************/
  103. private void
  104. rec_windup(){
  105.     if(record_buffer != (char *)NULL)
  106.         free(record_buffer);
  107. }
  108. /**********************************************************
  109. rec_variable - get a variable size record from standard input
  110. ***********************************************************/
  111. RECORD *
  112. rec_variable()
  113. {
  114.     RECORD *record_address;        /* pointer to record */
  115.     size_t record_length;
  116.  
  117.     /* make sure we don't fill the record buffer up */
  118.     if(rec_get(record_buffer, record_size , stdin)
  119.     == (char *)NULL)
  120.         return (RECORD *)NULL;
  121.     record_length = strlen(record_buffer);
  122.     record_address
  123.         = (RECORD *)mklinks(need(d_stack, data_size+record_length), 1);
  124.     memcpy(record_address->data+record_offset,
  125.         record_buffer, record_length + 1);
  126.  
  127.     /* if record data doesn't fit within buffer */
  128.     if(record_address->data[record_offset + record_length - 1] != '\n')
  129.         error("Record too long");
  130.  
  131.     record_address->field[0] = record_offset + record_length;
  132.     rec_fill(record_address);
  133.  
  134.     return record_address;
  135. }
  136. /**********************************************************
  137. rec_get - get a record from standard input
  138. ***********************************************************/
  139. private
  140. RECORD *
  141. rec_get(ptr, size, fptr)
  142. char *ptr;
  143. SEG_SIZE size;
  144. FILE *fptr;
  145. {
  146.     if(fgets(ptr, (int)size, fptr) == (char *)NULL){
  147.  
  148.         /* be sure its an end of file */
  149.         if(feof(fptr)){
  150.             /* if we're done, change future input source */
  151.             fclose(fptr);
  152.             /* and return NULL */
  153.             return (RECORD *)NULL;
  154.         }
  155.         else{
  156.             perror("I/O error in standard input");
  157.             exit(1);
  158.         }
  159.     }
  160. }
  161. /*********************************************************
  162. rec_fixed - get a fixed size record from standard input
  163. ***********************************************************/
  164. RECORD *
  165. rec_fixed()
  166. {
  167.     RECORD *record_address;    /* pointer to record including links and fields */
  168.     int record_read;
  169.     SEG_SIZE size;
  170.  
  171.     /* get space for input */
  172.     record_address
  173.         = (RECORD *)mklinks(need(d_stack, data_size + record_size), 1);
  174.     record_address->field[0] = record_offset + record_size;
  175.  
  176.     /* get a line of text from standard input */
  177.     record_read =
  178.         fread(record_address->data+record_offset, record_size, 1, stdin);
  179.  
  180.     /* add null terminator */
  181.     record_address->data[record_address->field[0]] = (char)NULL;
  182.  
  183.     if(record_read == 0){
  184.         /* be sure its an end of file */
  185.         if(feof(stdin)){
  186.             /* if we're done, change future input source */
  187.             fclose(stdin);
  188.             /* and return NULL */
  189.             return (RECORD *)NULL;
  190.         }
  191.         else{
  192.             assert(ferror(stdin))
  193.             perror("I/O error in standard input");
  194.             exit(1);
  195.         }
  196.     }
  197.     rec_fill(record_address);
  198.     return record_address;
  199. }
  200. /*********************************************************************
  201. rec_fill - give a record, fill in the field pointers
  202. **********************************************************************/
  203. private
  204. void
  205. rec_fill(record_address)
  206. RECORD *record_address;    /* pointer to record */
  207. {
  208.     unsigned int
  209.         i,             /* index into field sequence array */
  210.         fstart;     /* start of numeric field */
  211.     static int
  212.         sign,        /* +1 or -1 depending on sign of field */
  213.          offset,        /* offset to record data */
  214.          noffset;    /* offset to filled numeric data */
  215.     char *tptr, *eptr, c;
  216.  
  217.     /* figure where data starts */
  218.     tptr = record_address->data + record_offset;
  219.     eptr = record_address->data + record_address->field[0];
  220.  
  221.     /* find where fields start */
  222.     tab[0] = record_offset;
  223.     i = 1;
  224.     while(i < tab_count){
  225.         while(!isdelim(*tptr++)){
  226.             if(tptr >= eptr){
  227.                 goto fini;
  228.             }
  229.         }
  230.         tab[i++] = tptr - record_address->data;
  231.     }
  232.     fini:
  233.     /* missing fields all point to null */
  234.     while(i < tab_count)
  235.         tab[i++] = record_address->field[0];
  236.  
  237.     noffset = data_offset;
  238.     for(i = 0 ; i < key_count; ++i){
  239.         if(key[i].key_type == DEFAULT){
  240.             offset = tab[key[i].rfield+1] - tab[key[i].rfield];
  241.             offset = min(offset-1, key[i].disp) + tab[key[i].rfield];
  242.             assert(record_address);
  243.             record_address->field[i+1] = offset;
  244.         }
  245.         else{
  246.             /* Next 3 keys should be SIGN, NUMERIC, and FRACTION */
  247.             offset = tab[key[i].rfield+1] - tab[key[i].rfield];
  248.             offset = min(offset-1, key[i].disp) + tab[key[i].rfield];
  249.             /* skip leading spaces */
  250.             while(record_address->data[offset] == ' ')
  251.                 ++offset;
  252.             c = record_address->data[offset];
  253.             sign = 1;
  254.             if('+' == c)
  255.                 ++offset;
  256.             else
  257.             if('-' == c){
  258.                 sign = -1;
  259.                 ++offset;
  260.             }
  261.             while(record_address->data[offset] == '0')
  262.                 ++offset;
  263.             fstart = offset;
  264.             while(key[i + 1].seq->value[record_address->data[offset]])
  265.                 ++offset;
  266.             assert(record_address);
  267.             record_address->data[noffset] = sign * (offset - fstart + 1);
  268.             record_address->field[i + 1] = noffset++;
  269.             record_address->field[i + 2] = fstart;
  270.  
  271.             /* skip . or , if exists */
  272.             c = record_address->data[offset];
  273.             if(c == '.' || c == ',')
  274.                 ++offset;
  275.             record_address->field[i + 3] = offset;
  276.             i += 3;
  277.         }
  278.     }
  279.     rec_memflag(record_address) = FALSE;
  280.     return;
  281. }
  282. /*********************************************************************
  283. rec_output - write one record to standard output
  284. **********************************************************************/
  285. void
  286. rec_output(record_address)
  287. RECORD *record_address;
  288. {
  289.     efwrite(record_address->data + record_offset,
  290.         record_address->field[0] - record_offset,
  291.         1, stdout);
  292. }
  293.